using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using Enuo.Dotnet.Core.Autowired;
using Enuo.Dotnet.Service;
using Enuo.Dotnet.Web.Utils;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;

namespace Enuo.Dotnet.Web
{

  public class Startup
  {
    public static readonly SymmetricSecurityKey symmetricKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("need_to_get_this_from_enviroment"));

    public const string CookieScheme = "CookieScheme";
    public Startup(IConfiguration configuration)
    {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    /// <summary>
    /// Autofac注册服务的地方,Autofac会自动调用
    /// </summary>
    /// <param name="containerBuilder"></param>
    public void ConfigureContainer(ContainerBuilder containerBuilder)
    {

      //获取所有控制器类型并使用属性注入
      Type[] controllersTypeAssembly = typeof(Startup).Assembly.GetExportedTypes()
          .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
      containerBuilder.RegisterTypes(controllersTypeAssembly).PropertiesAutowired(new AutowiredPropertySelector());

      //containerBuilder.RegisterType<OrderService>().As<IOrderService>();
      //批量自动注入,把需要注入层的程序集传参数
      containerBuilder.BatchAutowired(typeof(ArticleService).Assembly);
      //containerBuilder.BatchAutowired(typeof(AuthenticateService).Assembly);
    }

    public static readonly ILoggerFactory efLogger = LoggerFactory.Create(builder =>
    {
#if DEBUG
      builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();
#endif
    });

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
      //services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));
      //services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));

      //让控制器实例由容器创建
      services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
      services.AddControllersWithViews();

      services.AddDbContext<MySqlDbContext>(options => 
        options.UseMySQL(Configuration.GetConnectionString("MySqlDbContext"), b => b.MigrationsAssembly("Enuo.Dotnet.Web"))
        .UseLoggerFactory(efLogger)
      );

      //services.AddScoped<ArticleService>();
      //services.AddScoped(Assembly.GetAssembly(typeof(ArticleService)), "^Enuo.Dotnet.Service.*Service$");

      // Sets the default scheme to cookies
      services.AddAuthentication(CookieScheme).AddCookie(CookieScheme, options =>
      {
        options.AccessDeniedPath = "/Account/AccessDenied";
        options.LoginPath = "/Account/Login";
      });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
      //获取Autofac容器上下文信息
      IocManager.InitContainer(app.ApplicationServices.GetAutofacRoot());

      if (env.IsDevelopment())
      {
        app.UseDeveloperExceptionPage();
      }
      else
      {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
      }
      app.UseHttpsRedirection();
      app.UseStaticFiles();

      app.UseRouting();

      app.UseAuthentication();
      app.UseAuthorization();

      app.UseEndpoints(endpoints =>
      {
        endpoints.MapControllerRoute(
                  name: "default",
                  pattern: "{controller=Home}/{action=Index}/{id?}");
      });
    }
  }
}
